package com.twoscreen;

import java.util.List;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import org.json.JSONObject;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.twoscreen.test.Test;
import com.twoscreen.test.TestMethod;

@PersistenceCapable
public class Video {
	@NotPersistent
	private static PersistenceManager pm = PMF.get().getPersistenceManager();
	
	@NotPersistent
	private static final Logger log = Logger.getLogger("com.twoscreen.Video.java");
	
	@NotPersistent
	private static final String videoTitlePropertyName = "videoTitle";
	
	@NotPersistent
	private static final String viewerIdPropertyName = "viewerId";
	
	@NotPersistent
	private static final String imageUrlPathPropertyName = "imageUrlPath";
	
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Key key;
	
	@Persistent
	private String videoTitle;
	
	@Persistent
	private String viewerId;
	
	@Persistent
	private String imageUrlPath;
	
	@Persistent
	private Boolean enabled;
	 
	public Video(String videoId, String videoTitle, String imageUrlPath, String viewerId) {
		Key key = KeyFactory.createKey(Video.class.getSimpleName(), videoId);
		this.key = key;
		this.videoTitle = videoTitle;
		this.viewerId = viewerId;
		this.imageUrlPath = imageUrlPath;
		this.enabled = true;
		pm.makePersistent(this);
		log.info("Video added: id: " + videoId +
				" videoTitle: " + videoTitle +
				" viewerId: " + viewerId +
				" imageUrlPath: " + imageUrlPath);
	}

	public Key getKey() {
		return key;
	}

	public String getVideoTitle() {
		return videoTitle;
	}
	
	public String getViewerId() {
		return viewerId;
	}

	public String getImageUrlPath() {
		return imageUrlPath;
	}
	
	private void setEnabled(Boolean enabled) {
		this.enabled = enabled;
	}
	
	public Boolean getEnabled() {
		return enabled;
	}

	public static Logger getLog() {
		return log;
	}

	public static String getVideotitlepropertyname() {
		return videoTitlePropertyName;
	}

	public static String getImageurlpathpropertyname() {
		return imageUrlPathPropertyName;
	}
	
	/**
	 * Searches the data store for a Video object based on the 
	 * video ID passed
	 * @param videoId The video ID to search for
	 * @return matching Video object
	 */
	public static Video getVideo(String videoId) {
		Video video = null;
		try {
			Key key = KeyFactory.createKey(Video.class.getSimpleName(), videoId);
			video = pm.getObjectById(Video.class, key);
		} catch (Exception e) {
			log.warning("Video not found");
		}
		return video;
	}
	
	/**
	 * Sets the enabled property passed for the video ID passed
	 * @param videoId The video ID to update the status of
	 * @param enabled True if enabled False if disabled
	 */
	public static void setEnabled(String videoId, Boolean enabled) {
		try {
			PersistenceManager pm = PMF.get().getPersistenceManager();
			Key key = KeyFactory.createKey(Video.class.getSimpleName(), videoId);
			Video video = pm.getObjectById(Video.class, key);
			video.setEnabled(enabled);
			pm.close();
		} catch (Exception e) {
			log.severe("Failed to set enabled status as video ID " + videoId +
					" does not exist");
		}
		
	}
	
	/**
	 * Get an array of Video objects that are enabled for viewing interactive content
	 * @return List array of Video objects
	 */
	public static List<Video> getVideoWallData() {
		Query q = pm.newQuery(Video.class);
		q.setFilter("enabled == true");
		
		try {
			log.info("Getting results");
			@SuppressWarnings("unchecked")
			List<Video> results = (List<Video>) q.execute();
			log.info("Returning " + results.size() + " results");
			return results;
		} finally {
			q.closeAll();
		}
	}
	
	/**
	 * Returns a JSON Object of Video ID's for a given viewer ID
	 * the field name is "videoID"
	 * 
	 * Used in EventServlet
	 * @param viewerId The viewer ID to search
	 * @return JSON Object of video ID's
	 */
	public static String getEnabledVideosJson(String viewerId) {
		log.info("Getting user's videos in JSON format for viewer ID: " + viewerId);
		String jsonReply = "";
		
		StringBuilder sb = new StringBuilder();
		sb.append("{ \"videoID\": [");
		
		Query q = pm.newQuery(Video.class);
		q.setFilter("enabled == true && " + viewerIdPropertyName + " == videoIdParam");
		q.declareParameters("String videoIdParam");
		try {
			log.info("Getting results");
			@SuppressWarnings("unchecked")
			List<Video> videos = (List<Video>) q.execute(viewerId);
			log.info("Returning " + videos.size() + " results");
			for (Video video : videos) {
				String videoID = video.getKey().getName();
				sb.append("\"" + videoID + "\",");
			}
		} finally {
			q.closeAll();
		}
		
		if (sb.length() > 17) {
			log.info("Character to be deleted: " + sb.charAt((sb.length()-1)));
			sb.deleteCharAt((sb.length()-1));
		}
		
		sb.append("]}");
		jsonReply = sb.toString();
		
		log.info("returning string: " + jsonReply);
		return jsonReply;
	}
	
	/**
	 * Runs all the tests on the class
	 * @return Test results JSON
	 */
	public static JSONObject test() {
		Test test = new Test("Video");
		test.addMethod(testConstructor());
		test.addMethod(testGetVideo());
		test.addMethod(testSetEnabled());
		test.addMethod(testGetVideoWallData());
		test.addMethod(testGetEnabledVideosJson());
		return test.getJSONObject();
	}
	
	/**
	 * Tests the constructor method
	 * @return Test results JSON
	 */
	private static JSONObject testConstructor() {
		TestMethod tm = new TestMethod("testConstructor");
		
		//Test base
		String videoId = "abcd";
		String videoTitle = "efgh";
		String imageUrlPath = "ijkl";
		String viewerId = "mnop";
		Video test = new Video(videoId, videoTitle, imageUrlPath, viewerId);
    	
		//Test 1
		Boolean test1 = false;
    	String testStack1 = "";
    	try {
    		Video inTest = pm.getObjectById(Video.class, test.getKey().getId());
    		test1 = (inTest != null);
    	} catch (Exception e) {
    		testStack1 = e.getMessage();
    	}
		tm.addTest("Entry exists", test1, testStack1);
		
		//Remove the test object
		pm.deletePersistent(test);
		
    	return tm.getJSONObject();
    }
	
	/**
	 * Tests the getVideo method
	 * @return Test results JSON
	 */
	private static JSONObject testGetVideo() {
		TestMethod tm = new TestMethod("testGetVideo");
		
		//Test base
		String videoId = "abcd";
		String videoTitle = "efgh";
		String imageUrlPath = "ijkl";
		String viewerId = "mnop";
		Video test = new Video(videoId, videoTitle, imageUrlPath, viewerId);
    	
		//Test 1
		Boolean test1 = false;
    	String testStack1 = "";
    	try {
    		Video inTest = getVideo(videoId);
    		test1 = (inTest != null);
    	} catch (Exception e) {
    		testStack1 = e.getMessage();
    	}
		tm.addTest("Entry exists", test1, testStack1);
		
		//Remove the test object
		pm.deletePersistent(test);
		
    	return tm.getJSONObject();
    }
	
	/**
	 * Tests the setEnabled method
	 * @return Test results JSON
	 */
	private static JSONObject testSetEnabled() {
		TestMethod tm = new TestMethod("testSetEnabled");
		
		//Test base
		String videoId = "abcd";
		String videoTitle = "efgh";
		String imageUrlPath = "ijkl";
		String viewerId = "mnop";
		Video test = new Video(videoId, videoTitle, imageUrlPath, viewerId);
		setEnabled(videoId, false);
    	
		//Test 1
		Boolean test1 = false;
    	String testStack1 = "";
    	try {
    		test1 = (test.getEnabled() == false);
    	} catch (Exception e) {
    		testStack1 = e.getMessage();
    	}
		tm.addTest("Setter test", test1, testStack1);
		
		//Remove the test object
		pm.deletePersistent(test);
		
    	return tm.getJSONObject();
    }
	
	/**
	 * Tests the getVideoWallData method
	 * @return Test results JSON
	 */
	private static JSONObject testGetVideoWallData() {
		TestMethod tm = new TestMethod("testGetVideoWallData");
    	
		//Test 1
		Boolean test1 = false;
    	String testStack1 = "";
    	try {
    		List<Video> inTest = getVideoWallData();
    		test1 = (inTest != null);
    	} catch (Exception e) {
    		testStack1 = e.getMessage();
    	}
		tm.addTest("Exists test", test1, testStack1);
		
    	return tm.getJSONObject();
    }
	
	/**
	 * Tests the getEnabledVideosJson method
	 * @return Test results JSON
	 */
	private static JSONObject testGetEnabledVideosJson() {
		TestMethod tm = new TestMethod("testGetEnabledVideosJson");
		
		//Test base
		String videoId = "abcd";
		String videoTitle = "efgh";
		String imageUrlPath = "ijkl";
		String viewerId = "mnop";
		Video test = new Video(videoId, videoTitle, imageUrlPath, viewerId);
		String tester = getEnabledVideosJson(viewerId);
    	
		//Test 1
		Boolean test1 = false;
    	String testStack1 = "";
    	try {
    		JSONObject inTest = new JSONObject(tester);
    		test1 = (inTest.has("videoID"));
    	} catch (Exception e) {
    		testStack1 = e.getMessage();
    	}
		tm.addTest("Is JSON", test1, testStack1);

		//Remove the test object
		pm.deletePersistent(test);
		
    	return tm.getJSONObject();
    }
	
}
